﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NetMicro.EventBus.Attributes;
using NetMicro.EventBus.Messages;

namespace NetMicro.EventBus.Extensions
{
    /// <summary>
    /// 重试扩展
    /// </summary>
    public static class RetryExtensions
    {
        /// <summary>
        /// 重试策略
        /// </summary>
        private static readonly Dictionary<string, TimeSpan[]> RetryKeyValue = new Dictionary<string, TimeSpan[]>();

        /// <summary>
        /// 添加重试策略
        /// </summary>
        private static void AddRetry(string retryKey, TimeSpan[] spans) => RetryKeyValue.TryAdd(retryKey, spans);


        /// <summary>
        /// 获取重试策略
        /// </summary>
        public static TimeSpan? GetRetry(this MessageTransfer transfer, int retryCount) => RetryKeyValue.TryGetValue(RetryKey(transfer), out TimeSpan[] spans)
                ? spans.Length > retryCount ? (TimeSpan?)spans[retryCount] : null
                : null;

        /// <summary>
        /// 是否存在重试策略
        /// </summary>
        public static bool HaveRetry(this MessageTransfer transfer, int retryCount) => RetryKeyValue.TryGetValue(RetryKey(transfer), out TimeSpan[] retry) && retry.Length > retryCount;

        /// <summary>
        /// 添加重试策略
        /// </summary>
        /// <param name="options"></param>
        /// <param name="hostName"></param>
        /// <returns></returns>
        public static EventBusOptions UseMessageRetry<TEventHandler, TEvent>(this EventBusOptions options, params TimeSpan[] intervals)
            where TEventHandler : IHandler
            where TEvent : IEvent
        {
            if (intervals.Length == 0)
                return options;
            AddRetry(RetryKey<TEventHandler, TEvent>(options), intervals);
            return options;
        }


        /// <summary>
        /// 添加重试策略
        /// </summary>
        /// <param name="options"></param>
        /// <param name="hostName"></param>
        /// <returns></returns>
        public static EventBusOptions UseMessageRetry<TEventHandler, TEvent>(this EventBusOptions options, int retryCount, TimeSpan interval)
                 where TEventHandler : IHandler
                 where TEvent : IEvent
        {
            TimeSpan[] intervals = Enumerable.Repeat(interval, retryCount).ToArray();
            AddRetry(RetryKey<TEventHandler, TEvent>(options), intervals);
            return options;
        }



        /// <summary>
        /// 获取重试key
        /// </summary>
        /// <typeparam name="TEventHandler"></typeparam>
        /// <typeparam name="TEvent"></typeparam>
        /// <param name="options"></param>
        /// <returns></returns>
        private static string RetryKey<TEventHandler, TEvent>(EventBusOptions options)
         where TEventHandler : IHandler
         where TEvent : IEvent => $"{typeof(TEventHandler).GetCustomAttribute<EventHandlerAttribute>()?.Name}.{options.Version}-{typeof(TEvent).GetCustomAttribute<EventNameAttribute>()?.Name}.{options.Version}";
        /// <summary>
        /// 获取重试key
        /// </summary>
        /// <param name="eventHandlerName"></param>
        /// <param name="eventName"></param>
        /// <returns></returns>
        private static string RetryKey(MessageTransfer transfer) => $"{transfer.EventHandlerName}-{transfer.EventName}";
    }
}
